home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #2 / Monster Media No. 2 (Monster Media)(1994).ISO / prog_pas / sk210f.zip / SHLIST.PAS < prev    next >
Pascal/Delphi Source File  |  1994-05-11  |  22KB  |  677 lines

  1. {$I SHDEFINE.INC}
  2.  
  3. {$I SHUNITSW.INC}
  4.  
  5. {$D-,L-}
  6. {$A-,V-}
  7. unit ShList;
  8. {
  9.                                  ShList
  10.  
  11.                          A List Processing Unit
  12.  
  13.                                    by
  14.  
  15.                               Bill Madison
  16.  
  17.                    W. G. Madison and Associates, Ltd.
  18.                           13819 Shavano Downs
  19.                             P.O. Box 780956
  20.                        San Antonio, TX 78278-0956
  21.                              (512)492-2777
  22.                              CIS 73240,342
  23.                 Internet bill.madison@lchance.sat.tx.us
  24.  
  25.                 Copyright 1990, '94 Madison & Associates
  26.                           All Rights Reserved
  27.  
  28.         This file may  be used and distributed  only in accord-
  29.         ance with the provisions described on the title page of
  30.                   the accompanying documentation file
  31.                               SKYHAWK.DOC
  32. }
  33.  
  34. interface
  35.  
  36. uses
  37.   TpString,
  38.   TpInline,
  39.   TpMemChk;
  40.  
  41. const
  42.   Copyr = 'Copyright 1990, 1994 by W.G. Madison';
  43.  
  44. type
  45.   slNodePtr = ^slNode;
  46.   slNode    = record
  47.                 Data  : pointer;
  48.                 Next  : slNodePtr;
  49.                 end;
  50.   dlNodePtr = ^dlNode;
  51.   dlNode    = record
  52.                 Data  : pointer;
  53.                 Next,
  54.                 Prev  : dlNodePtr;
  55.                 end;
  56.   slList    = record
  57.                 DataRecSize : word;
  58.                 Count       : LongInt;
  59.                 Head,
  60.                 Tail,
  61.                 Current     : slNodePtr;
  62.                 end;
  63.   dlList    = record
  64.                 DataRecSize : word;
  65.                 Count       : LongInt;
  66.                 Head,
  67.                 Tail,
  68.                 Current     : dlNodePtr;
  69.                 end;
  70.   dlLessFunc= function(var DataRec1, DataRec2)  : boolean;
  71.  
  72. {******************INITIALIZATION ROUTINES************************}
  73.  
  74. procedure slListInit(var L  : slList; RecSize : word);
  75. {Initializes a singly linked list.}
  76.  
  77. procedure dlListInit(var L : dlList; RecSize : word);
  78. {Initializes a doubly linked list.}
  79.  
  80. {******************STORAGE ROUTINES************************}
  81.  
  82. function slPush(var L : slList; var DataRec) : boolean;
  83. function dlPush(var L : dlList; var DataRec) : boolean;
  84. {Pushes a data record onto the top of the list.}
  85.  
  86. function slAppend(var L : slList; var DataRec) : boolean;
  87. function dlAppend(var L : dlList; var DataRec) : boolean;
  88. {Appends a data record to the tail of the list.}
  89.  
  90. function slPut(var L : slList; var DataRec) : boolean;
  91. function dlPut(var L : dlList; var DataRec) : boolean;
  92. {Inserts a data record following the current node; returns with current
  93.  pointer directed to the new node.}
  94.  
  95. function dlPutPrev(var L : dlList; var DataRec) : boolean;
  96. {Inserts a data record ahead of the current node; returns with current
  97.  pointer directed to the new node.}
  98.  
  99. function dlPutSorted(var L : dlList;
  100.                         var DataRec; Less : dlLessFunc) : boolean;
  101. {Inserts a data record into the list in sorted order, as determined by
  102.  the user-defined boolean function LESS.}
  103.  
  104. procedure slFree(var L : slList);
  105. procedure dlFree(var L : dlList);
  106. {Releases the heap space allocated for a list and re-initializes the
  107.  list.}
  108.  
  109. {******************RETRIEVAL ROUTINES************************}
  110.  
  111. function slGetCurrent(var L : slList; var DataRec) : boolean;
  112. {Returns the data record at the current node and does not move the node
  113.  pointer. Returns a function value of false if the list is empty or the
  114.  current node pointer is nil.}
  115.  
  116. function dlGetCurrent(var L : dlList; var DataRec) : boolean;
  117. {Returns the data record at the current node and does not move the node
  118.  pointer. Returns a function value of false if the list is empty or the
  119.  current node pointer is nil.}
  120.  
  121. function slGetFirst(var L : slList; var DataRec) : boolean;
  122. {Returns the data record at the head of the list. Sets the current node
  123.  pointer to the head of the list. Returns a function value of false if
  124.  the list is empty.}
  125.  
  126. function dlGetFirst(var L : dlList; var DataRec) : boolean;
  127. {Returns the data record at the head of the list. Sets the current node
  128.  pointer to the head of the list. Returns a function value of false if
  129.  the list is empty.}
  130.  
  131. function slGetLast(var L : slList; var DataRec) : boolean;
  132. {Returns the data record at the tail of the list. Sets the current node
  133.  pointer to the tail of the list. Returns a function value of false if
  134.  the list is empty.}
  135.  
  136. function dlGetLast(var L : dlList; var DataRec) : boolean;
  137. {Returns the data record at the tail of the list. Sets the current node
  138.  pointer to the tail of the list. Returns a function value of false if
  139.  the list is empty.}
  140.  
  141. function slGetNext(var L : slList; var DataRec) : boolean;
  142. {Returns the next data record in the list. Sets the current node pointer
  143.  to the record retrieved. Returns a function value of false if the list is
  144.  empty or if the last record successfully retrieved was at the list tail.
  145.  In this case, calling slGetNext again will retrieve the head of the list.}
  146.  
  147. function dlGetNext(var L : dlList; var DataRec) : boolean;
  148. {Returns the next data record in the list. Sets the current node pointer
  149.  to the record retrieved. Returns a function value of false if the list is
  150.  empty or if the last record successfully retrieved was at the list tail.
  151.  In this case, calling dlGetNext again will retrieve the head of the list.}
  152.  
  153. function dlGetPrev(var L : dlList; var DataRec) : boolean;
  154. {Same as dlGetNext, but in the opposite direction.}
  155.  
  156. function slPop(var L : slList; var DataRec) : boolean;
  157. {Returns the data record at the head of the list, then deallocates the
  158.  space associated with the data record and node. Returns a function value
  159.  of false if the list is empty.}
  160.  
  161. function dlPop(var L : dlList; var DataRec) : boolean;
  162. {Returns the data record at the head of the list, then deallocates the
  163.  space associated with the data record and node. Returns a function value
  164.  of false if the list is empty.}
  165.  
  166. {******************GENERAL UTILITY ROUTINES************************}
  167.  
  168. function slCount(L : slList) : LongInt;
  169. {Returns the number of records currently in the list.}
  170.  
  171. function dlCount(L : dlList) : LongInt;
  172. {Returns the number of records currently in the list.}
  173.  
  174. function slSpaceUsed(L : slList) : LongInt;
  175. {Returns the total amount of heap space currently allocated to the list.}
  176.  
  177. function dlSpaceUsed(L : dlList) : LongInt;
  178. {Returns the total amount of heap space currently allocated to the list.}
  179.  
  180. function Ptr2Str(P : pointer) : string;
  181. {This function is included primarily for debugging.}
  182. {Returns a string of the form ssss:oooo being the hex representation of
  183.  the pointer P following normalization, in segment:offset form.}
  184.  
  185. {*******************************************************************}
  186. {*******************************************************************}
  187. implementation
  188. {*******************************************************************}
  189. {*******************************************************************}
  190.  
  191. {******************INTERNAL UTILITY ROUTINES************************}
  192.  
  193. function Ptr2Str(P:pointer) : string; {For debugging only!}
  194.   begin
  195.     Ptr2Str := HexPtr(Normalized(P));
  196.     end;
  197.  
  198. function slGrabMemory(var L : slList;
  199.                       var P : slNodePtr;
  200.                       var DataRec)        : boolean;
  201. {Gets the heap space needed for the node and its data record.}
  202.   begin
  203.     if GetMemCheck(P, SizeOf(slNode)) then begin
  204.       if GetMemCheck(P^.Data, L.DataRecSize) then begin
  205.         slGrabMemory := true;
  206.         Move(DataRec, P^.Data^, L.DataRecSize);
  207.         exit;
  208.         end
  209.       else {room for the node but not the data}
  210.         FreeMemCheck(P, SizeOf(slNode));
  211.       end;
  212.     {If we get to here, there has been a space allocation problem.}
  213.     slGrabMemory := false;
  214.     end;  {slGrabMemory}
  215.  
  216. function dlGrabMemory(var L : dlList;
  217.                       var P : dlNodePtr;
  218.                       var DataRec)        : boolean;
  219. {Gets the heap space needed for the node and its data record.}
  220.   begin
  221.     if GetMemCheck(P, SizeOf(dlNode)) then begin
  222.       if GetMemCheck(P^.Data, L.DataRecSize) then begin
  223.         dlGrabMemory := true;
  224.         Move(DataRec, P^.Data^, L.DataRecSize);
  225.         exit;
  226.         end
  227.       else {room for the node but not the data}
  228.         FreeMemCheck(P, SizeOf(dlNode));
  229.       end;
  230.     {If we get to here, there has been a space allocation problem.}
  231.     dlGrabMemory := false;
  232.     end;  {dlGrabMemory}
  233.  
  234. function slFirstNode(var L : slList; var P : slNodePtr) : boolean;
  235. {If list L is empty and the first node has been allocated, sets up the
  236.  pointers. Assumes that the node has been allocated with slGrabMemory.
  237.  Returns a function value of false if the list is not empty.}
  238.   begin
  239.     L.Current := P;
  240.     if L.Count = 0 then begin
  241.       slFirstNode := true;
  242.       P^.Next := nil;
  243.       L.Head := P;
  244.       L.Tail := P;
  245.       end
  246.     else
  247.       slFirstNode := false;
  248.     end; {slFirstNode}
  249.  
  250. function dlFirstNode(var L : dlList; var P : dlNodePtr) : boolean;
  251. {If list L is empty and the first node has been allocated, sets up the
  252.  pointers. Assumes that the node has been allocated with dlGrabMemory.
  253.  Returns a function value of false if the list is not empty.}
  254.   var
  255.     B1  : boolean;
  256.   begin
  257.     B1 := slFirstNode(slList(L), slNodePtr(P));
  258.     if B1 then
  259.       P^.Prev := nil;
  260.     dlFirstNode := B1;
  261.     end; {dlFirstNode}
  262.  
  263. {******************INITIALIZATION ROUTINES************************}
  264.  
  265. procedure slListInit(var L  : slList; RecSize : word);
  266. {Initializes a singly linked list.}
  267.   begin
  268.     with L do begin
  269.       DataRecSize := RecSize;
  270.       Count := 0;
  271.       Head := nil;
  272.       Tail := nil;
  273.       Current := nil;
  274.       end; {with}
  275.     end; {slListInit}
  276.  
  277. procedure dlListInit(var L : dlList; RecSize : word);
  278. {Initializes a doubly linked list.}
  279.   begin
  280.     slListInit(slList(L), RecSize);
  281.     end; {dlListInit}
  282.  
  283. {******************STORAGE ROUTINES************************}
  284.  
  285. function slPush(var L : slList; var DataRec) : boolean;
  286. {Pushes a data record onto the top of the list.}
  287.   var
  288.     P : slNodePtr;
  289.   begin
  290.     if not slGrabMemory(L, P, DataRec) then begin
  291.       slPush := false;
  292.       exit;
  293.       end;
  294.     slPush := true;
  295.     if not slFirstNode(L, P) then begin
  296.       P^.Next := L.Head;
  297.       L.Head := P;
  298.       end;
  299.     inc(L.Count);
  300.     end; {slPush}
  301.  
  302. function dlPush(var L : dlList; var DataRec) : boolean;
  303. {Pushes a data record onto the top of the list.}
  304.   var
  305.     P : dlNodePtr;
  306.   begin
  307.     if not dlGrabMemory(L, P, DataRec) then begin
  308.       dlPush := false;
  309.       exit;
  310.       end;
  311.     dlPush := true;
  312.     if not dlFirstNode(L, P) then begin
  313.       P^.Next := L.Head;
  314.       L.Head^.Prev := P;
  315.       L.Head := P;
  316.       L.Head^.Prev := nil;
  317.       end;
  318.     inc(L.Count);
  319.     end; {dlPush}
  320.  
  321. function slAppend(var L : slList; var DataRec) : boolean;
  322. {Appends a data record to the tail of the list.}
  323.   var
  324.     P : slNodePtr;
  325.   begin
  326.     if not slGrabMemory(L, P, DataRec) then begin
  327.       slAppend := false;
  328.       exit;
  329.       end;
  330.     slAppend := true;
  331.     if not slFirstNode(L, P) then begin
  332.       L.Tail^.Next := P;
  333.       L.Tail := P;
  334.       L.Tail^.Next := nil;
  335.       end;
  336.     inc(L.Count);
  337.     end; {slAppend}
  338.  
  339. function dlAppend(var L : dlList; var DataRec) : boolean;
  340. {Appends a data record to the tail of the list.}
  341.   var
  342.     P : dlNodePtr;
  343.   begin
  344.     if not dlGrabMemory(L, P, DataRec) then begin
  345.       dlAppend := false;
  346.       exit;
  347.       end;
  348.     dlAppend := true;
  349.     if not dlFirstNode(L, P) then begin
  350.       L.Tail^.Next := P;
  351.       P^.Prev := L.Tail;
  352.       L.Tail := P;
  353.       L.Tail^.Next := nil;
  354.       end;
  355.     inc(L.Count);
  356.     end; {dlAppend}
  357.  
  358. function slPut(var L : slList; var DataRec) : boolean;
  359. {Inserts a data record following the current node; returns with current
  360.  pointer directed to the new node.}
  361.   var
  362.     P,
  363.     C : slNodePtr;
  364.   begin
  365.     if not slGrabMemory(L, P, DataRec) then begin
  366.       slPut := false;
  367.       exit;
  368.       end;
  369.     slPut := true;
  370.     C := L.Current;
  371.     if not slFirstNode(L, P) then begin
  372.       L.Current^.Next := C^.Next;
  373.       C^.Next := L.Current;
  374.       end;
  375.     if L.Current^.Next = nil then
  376.       L.Tail := L.Current;
  377.     inc(L.Count);
  378.     end; {slPut}
  379.  
  380. function dlPut(var L : dlList; var DataRec) : boolean;
  381. {Inserts a data record following the current node; returns with current
  382.  pointer directed to the new node.}
  383.   var
  384.     P,
  385.     C : dlNodePtr;
  386.   begin
  387.     if not dlGrabMemory(L, P, DataRec) then begin
  388.       dlPut := false;
  389.       exit;
  390.       end;
  391.     dlPut := true;
  392.     C := L.Current;
  393.     if not dlFirstNode(L, P) then begin
  394.       L.Current^.Next := C^.Next;
  395.       C^.Next := L.Current;
  396.       L.Current^.Prev := C;
  397.       if L.Current^.Next <> nil then begin
  398.         L.Current^.Next^.Prev := L.Current;
  399.         end;
  400.       end;
  401.     if L.Current^.Next = nil then
  402.       L.Tail := L.Current;
  403.     inc(L.Count);
  404.     end; {dlPut}
  405.  
  406. function dlPutPrev(var L : dlList; var DataRec) : boolean;
  407. {Inserts a data record ahead of the current node; returns with current
  408.  pointer directed to the new node.}
  409.   var
  410.     P,
  411.     C : dlNodePtr;
  412.   begin
  413.     if not dlGrabMemory(L, P, DataRec) then begin
  414.       dlPutPrev := false;
  415.       exit;
  416.       end;
  417.     dlPutPrev := true;
  418.     C := L.Current;
  419.     if not dlFirstNode(L, P) then begin
  420.       L.Current^.Prev := C^.Prev;
  421.       C^.Prev := L.Current;
  422.       L.Current^.Next := C;
  423.       L.Current^.Prev^.Next := L.Current;
  424.       end;
  425.     if L.Current^.Prev = nil then
  426.       L.Head := L.Current;
  427.     inc(L.Count);
  428.     end; {dlPutPrev}
  429.  
  430. function dlPutSorted(var L : dlList;
  431.                         var DataRec; Less : dlLessFunc) : boolean;
  432. {Inserts a data record into the list in sorted order, as determined by
  433.  the user-defined boolean function LESS.}
  434.   var
  435.     DataRec0  : pointer;
  436.   begin
  437.     if L.Count = 0 then begin                 {Empty list}
  438.       dlPutSorted := dlPut(L, DataRec);
  439.       exit;
  440.       end;
  441.     if not GetMemCheck(DataRec0, L.DataRecSize) then begin
  442.       dlPutSorted := false;
  443.       exit;
  444.       end;
  445.     if not dlGetCurrent(L, DataRec0^) then begin
  446.       if dlGetLast(L, DataRec0^) then ;
  447.       if Less(DataRec0^, DataRec) then begin
  448.         dlPutSorted := dlAppend(L, DataRec);
  449.         FreeMemCheck(DataRec0, L.DataRecSize);
  450.         exit;
  451.         end;
  452.       if dlGetFirst(L, DataRec0^) then ;
  453.       if not Less(DataRec0^, DataRec) then begin
  454.         dlPutSorted := dlPush(L, DataRec);
  455.         FreeMemCheck(DataRec0, L.DataRecSize);
  456.         exit;
  457.         end;
  458.       end; {if not dlGetCurrent}
  459.     if Less(DataRec0^, DataRec) then begin
  460.       while dlGetNext(L, DataRec0^) and Less(DataRec0^, DataRec) do ;
  461.       if not Less(DataRec0^, DataRec) then begin
  462.         dlPutSorted := dlPutPrev(L, DataRec);
  463.         end
  464.       else begin
  465.         dlPutSorted := dlAppend(L, DataRec);
  466.         end
  467.       end {if Less}
  468.     else begin
  469.       while dlGetPrev(L, DataRec0^) and not Less(DataRec0^, DataRec) do ;
  470.       if Less(DataRec0^, DataRec) then
  471.         dlPutSorted := dlPut(L, DataRec)
  472.       else
  473.         dlPutSorted := dlPush(L, DataRec);
  474.       end; {else}
  475.     FreeMemCheck(DataRec0, L.DataRecSize);
  476.     end; {dlPutSorted}
  477.  
  478. procedure slFree(var L : slList);
  479. {Releases the heap space allocated for a list and re-initializes the
  480.  list.}
  481.   var
  482.     T1  : LongInt;
  483.     P   : slNodePtr;
  484.   begin
  485.     for T1 := 1 to L.Count do begin
  486.       P := L.Head;
  487.       L.Head := P^.Next;
  488.       FreeMemCheck(P^.Data, L.DataRecSize);
  489.       FreeMemCheck(P, SizeOf(slNode));
  490.       end;
  491.     slListInit(L, L.DataRecSize);
  492.     end; {slFree}
  493.  
  494. procedure dlFree(var L : dlList);
  495. {Releases the heap space allocated for a list and re-initializes the
  496.  list.}
  497.   var
  498.     T1  : LongInt;
  499.     P   : dlNodePtr;
  500.   begin
  501.     for T1 := 1 to L.Count do begin
  502.       P := L.Head;
  503.       L.Head := P^.Next;
  504.       FreeMemCheck(P^.Data, L.DataRecSize);
  505.       FreeMemCheck(P, SizeOf(dlNode));
  506.       end;
  507.     dlListInit(L, L.DataRecSize);
  508.     end; {dlFree}
  509.  
  510. {******************RETRIEVAL ROUTINES************************}
  511.  
  512. function slGetCurrent(var L : slList; var DataRec) : boolean;
  513. {Returns the data record at the current node and does not move the node
  514.  pointer. Returns a function value of false if the list is empty or the
  515.  current node pointer is nil.}
  516.   begin
  517.     if L.Current = nil then begin
  518.       slGetCurrent := false;
  519.       exit;
  520.       end;
  521.     slGetCurrent := true;
  522.     Move(L.Current^.Data^, DataRec, L.DataRecSize);
  523.     end; {slGetCurrent}
  524.  
  525. function dlGetCurrent(var L : dlList; var DataRec) : boolean;
  526. {Returns the data record at the current node and does not move the node
  527.  pointer. Returns a function value of false if the list is empty or the
  528.  current node pointer is nil.}
  529.   var
  530.     S : slList absolute L;
  531.   begin
  532.     dlGetCurrent := slGetCurrent(S, DataRec);
  533.     end; {dlGetCurrent}
  534.  
  535. function slGetFirst(var L : slList; var DataRec) : boolean;
  536. {Returns the data record at the head of the list. Sets the current node
  537.  pointer to the head of the list. Returns a function value of false if
  538.  the list is empty.}
  539.   begin
  540.     L.Current := L.Head;
  541.     slGetFirst := slGetCurrent(L, DataRec);
  542.     end; {slGetFirst}
  543.  
  544. function dlGetFirst(var L : dlList; var DataRec) : boolean;
  545. {Returns the data record at the head of the list. Sets the current node
  546.  pointer to the head of the list. Returns a function value of false if
  547.  the list is empty.}
  548.   var
  549.     S : slList absolute L;
  550.   begin
  551.     dlGetFirst := slGetFirst(S, DataRec);
  552.     end; {dlGetFirst}
  553.  
  554. function slGetLast(var L : slList; var DataRec) : boolean;
  555. {Returns the data record at the tail of the list. Sets the current node
  556.  pointer to the tail of the list. Returns a function value of false if
  557.  the list is empty.}
  558.   begin
  559.     L.Current := L.Tail;
  560.     slGetLast := slGetCurrent(L, DataRec);
  561.     end; {slGetLast}
  562.  
  563. function dlGetLast(var L : dlList; var DataRec) : boolean;
  564. {Returns the data record at the tail of the list. Sets the current node
  565.  pointer to the tail of the list. Returns a function value of false if
  566.  the list is empty.}
  567.   var
  568.     S : slList absolute L;
  569.   begin
  570.     dlGetLast := slGetLast(S, DataRec);
  571.     end; {dlGetLast}
  572.  
  573. function slGetNext(var L :slList; var DataRec) : boolean;
  574. {Returns the next data record in the list. Sets the current node pointer
  575.  to the record retrieved. Returns a function value of false if the list is
  576.  empty or if the last record successfully retrieved was at the list tail.
  577.  In this case, calling slGetNext again will retrieve the head of the list.}
  578.   begin
  579.     if not (L.Count = 0) then begin
  580.       if L.Current = nil then
  581.         L.Current := L.Head
  582.       else
  583.         L.Current := L.Current^.Next;
  584.       end; {if not L.Count}
  585.     slGetNext := slGetCurrent(L, DataRec);
  586.     end; {slGetNext}
  587.  
  588. function dlGetNext(var L : dlList; var DataRec) : boolean;
  589. {Returns the next data record in the list. Sets the current node pointer
  590.  to the record retrieved. Returns a function value of false if the list is
  591.  empty or if the last record successfully retrieved was at the list tail.
  592.  In this case, calling dlGetNext again will retrieve the head of the list.}
  593.   var
  594.     S : slList absolute L;
  595.   begin
  596.     dlGetNext := slGetNext(S, DataRec);
  597.     end; {dlGetNext}
  598.  
  599. function dlGetPrev(var L : dlList; var DataRec) : boolean;
  600. {Same as dlGetNext, but in the opposite direction.}
  601.   begin
  602.     if not (L.Count = 0) then begin
  603.       if L.Current = nil then
  604.         L.Current := L.Tail
  605.       else
  606.         L.Current := L.Current^.Prev;
  607.       end; {if not L.Count}
  608.     dlGetPrev := dlGetCurrent(L, DataRec);
  609.     end; {dlGetPrev}
  610.  
  611. function slPop(var L : slList; var DataRec) : boolean;
  612. {Returns the data record at the head of the list, then deallocates the
  613.  space associated with the data record and node. Returns a function value
  614.  of false if the list is empty.}
  615.   var
  616.     P : slNodePtr;
  617.     B : boolean;
  618.   begin
  619.     B := slGetFirst(L, DataRec);
  620.     slPop := B;
  621.     if not B then exit;
  622.     P := L.Head;
  623.     L.Head := P^.Next;
  624.     L.Current := L.Head;
  625.     FreeMemCheck(P^.Data, L.DataRecSize);
  626.     FreeMemCheck(P, SizeOf(slNode));
  627.     dec(L.Count);
  628.     end; {slPop}
  629.  
  630. function dlPop(var L : dlList; var DataRec) : boolean;
  631. {Returns the data record at the head of the list, then deallocates the
  632.  space associated with the data record and node. Returns a function value
  633.  of false if the list is empty.}
  634.   var
  635.     P : dlNodePtr;
  636.     B : boolean;
  637.   begin
  638.     B := dlGetFirst(L, DataRec);
  639.     dlPop := B;
  640.     if not B then exit;
  641.     P := L.Head;
  642.     L.Head := P^.Next;
  643.     if L.Head <> nil then
  644.       L.Head^.Prev := nil;
  645.     L.Current := L.Head;
  646.     FreeMemCheck(P^.Data, L.DataRecSize);
  647.     FreeMemCheck(P, SizeOf(dlNode));
  648.     dec(L.Count);
  649.     end; {dlPop}
  650.  
  651. {******************GENERAL UTILITY ROUTINES************************}
  652.  
  653. function slCount(L : slList) : LongInt;
  654. {Returns the number of records currently in the list.}
  655.   begin
  656.     slCount := L.Count;
  657.     end; {slCount}
  658.  
  659. function dlCount(L : dlList) : LongInt;
  660. {Returns the number of records currently in the list.}
  661.   begin
  662.     dlCount := L.Count;
  663.     end; {dlCount}
  664.  
  665. function slSpaceUsed(L : slList) : LongInt;
  666. {Returns the total amount of heap space currently allocated to the list.}
  667.   begin
  668.     slSpaceUsed := L.Count * (L.DataRecSize + SizeOf(slNode));
  669.     end; {slSpaceUsed}
  670.  
  671. function dlSpaceUsed(L : dlList) : LongInt;
  672. {Returns the total amount of heap space currently allocated to the list.}
  673.   begin
  674.     dlSpaceUsed := L.Count * (L.DataRecSize + SizeOf(dlNode));
  675.     end; {dlSpaceUsed}
  676.   end.
  677.